/**
 * 
 */
package gui.views;

import gui.CharacterInsertionButton;
import gui.LibraryComboBox;
import gui.OperatorComboBox;
import gui.OperatorWidget;
import gui.OperatorWidget.TypeLabel;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import metagrammar.Operator;
import parsetree.ElementFactory;
import parsetree.OperatorSpec;
import parsetree.util.OperatorSpecFactory;
import application.Application;
import application.GlobalContext;

import com.google.common.base.Splitter;
import com.google.common.collect.Ranges;

/**
 * @author Joshua Lockerman
 *
 */
public class CreateSpecView extends JFrame {
    
    private final GlobalContext context;
    
    private JTextPane textPane;
    private DefaultStyledDocument doc;
    
    private Operator operator;
    
    
    public CreateSpecView()
    {
        this(Operator.undefinedOperator);
    }
    
    public CreateSpecView(Operator operator)
    {
        super("Create Spec");
        
        this.operator = operator;
        
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        
        context = Application.injector.getInstance(GlobalContext.class);
        
        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
        
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        
        add(createCreatorPanel());
        
        add(Box.createVerticalStrut(15));
        
        add(createButtonPanel());
        
        pack();
        setMinimumSize(getSize());
    }
    
    private Component createCreatorPanel()
    {
        final JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        
        panel.add(createTextPanel(), BorderLayout.CENTER);
        
        JPanel p = new JPanel();
        p.setLayout(new FlowLayout(FlowLayout.LEFT));
        LibraryComboBox lcb = new LibraryComboBox();
        p.add(lcb);
        final OperatorComboBox operatorSelector = lcb.createOperatorComboBox();
        p.add(operatorSelector);
        final JPanel p2 = new JPanel();
        p2.add(new OperatorWidget(textPane, operator));
        p.add(p2);
        panel.add(p, BorderLayout.NORTH);
        
        operatorSelector.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                operator = operatorSelector.getSelectedOperator();
                p2.removeAll();
                p2.add(new OperatorWidget(textPane, operator));
            }
        });
        
        panel.add(createToolBars(), BorderLayout.SOUTH);
        
        return panel;
    }
    
    /**
     * @return
     */
    private JComponent createTextPanel()
    {
        doc = new DefaultStyledDocument();
        SimpleAttributeSet center = new SimpleAttributeSet();
        StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
        doc.setParagraphAttributes(0, doc.getLength(), center, false);
        textPane = new JTextPane(doc);
        textPane.setEditable(true);
        JPanel textPanel = new JPanel();
        textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.Y_AXIS));
        textPanel.add(Box.createVerticalGlue());
        textPanel.add(textPane);
        JScrollPane edScroll = new JScrollPane(textPanel);
        edScroll.setPreferredSize(new Dimension(162, 92));
        return edScroll;
    }
    
    /**
     * @return
     */
    private JPanel createButtonPanel()
    {
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING));
        
        JButton okButton = new JButton();
        okButton.setAction(new AbstractAction("Create") {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                createOperatorSpec();
            }
        });
        buttonPanel.add(okButton);
        
        JButton cancelButton = new JButton();
        cancelButton.setAction(new AbstractAction("Cancel") {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                dispose();
            }
        });
        buttonPanel.add(cancelButton);
        return buttonPanel;
    }
    
    private Component createToolBars()
    {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        JToolBar toolbar = new JToolBar();
        JMenuBar menuBar = new JMenuBar();
        toolbar.add(menuBar);
        menuBar.add(new CharacterInsertionButton(textPane, Ranges.<Character> closed('α', 'ω')));
        menuBar.add(new CharacterInsertionButton(textPane, Ranges.<Character> closed('Α', 'Ω')));
        menuBar.add(new CharacterInsertionButton(textPane, Ranges.<Character> closed('+', '/'),
                Ranges.<Character> closed('\\', '`'), Ranges.<Character> closed('{', '~'), Ranges
                .singleton('¬'), Ranges.singleton('±'), Ranges.<Character> closed('˂', '˅')));
        panel.add(toolbar);
        return panel;
    }
    
    private void createOperatorSpec()
    {
        try {
            OperatorSpecFactory factory = OperatorSpecFactory.forOperator(operator);
            String text = textPane.getText();
            Iterable<String> substrings = Splitter.on(" ").split(text);
            int offset = 0;
            for(String sub : substrings) {
                if( !sub.equals("")) {
                    factory.followedBy(sub);
                }
                else {
                    Element element = doc.getCharacterElement(offset);
                    Object foundComponent = element.getAttributes().getAttribute(
                            StyleConstants.ComponentAttribute);
                    if(foundComponent instanceof TypeLabel) {
                        factory.followedByInput(((TypeLabel) foundComponent)
                                .getInputTuplePosition());
                    }
                    else {
                        //factory.followedBy(" ");
                    }
                }
                offset += sub.length();
            }
            ElementFactory spec = factory.createSpec();
            context.add((OperatorSpec) spec);
            JOptionPane.showMessageDialog(this, spec + " added.");
            //TODO
        }
        finally {
            dispose();
        }
    }
}
